iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 29
10
Software Development

前端工程師用 javaScript 學演算法系列 第 29

[有趣面試題] 網頁效能問題改善之 Debounce & Throttle

  • 分享至 

  • xImage
  •  

其實最後這一系列 “聊聊美國找工作以及面試經驗”,本來預計寫個 3 - 4 個有趣題目、至少 3 篇面試準備/異國工作心得,殊不知光資料結構跟演算法就佔用了28 天了?。只能各挪一篇給他們。等之後 30 天結束再不定期寫一下面試前需要準備的事好了。


我過去是在專案公司上班,要馬使用者不多、要馬後台資料量不大,所以我在調效能方面總是很不上心 (完全不會為了快 0.01 秒多花好幾天時間去寫。專案公司根本也不會給你太多時間時做)。所以當第一次看到有 Debounce & Throttle 跟這種概念覺得非常聰明啊 !!! 聽說也是大公司面試很常考的題目之一

適用情境

只要是使用者會在短時間內頻繁觸發多次事件處理器,例如 autocomplete、滑鼠移動、改變視窗大小都可以適用此篇。因為你的瀏覽器會不斷重新計算造成頁面很緩慢
https://ithelp.ithome.com.tw/upload/images/20190930/20106426sZqbVZU44W.png
在開始之前可以看一下這個網站感受不同方法的區別。

以 autocomplete 為例

此篇就以 autocomplete 為例,什麼是 autocomplete 呢?
https://ithelp.ithome.com.tw/upload/images/20190930/201064262aOIsW1ZAu.jpg
就是會有一個搜尋的 input
https://ithelp.ithome.com.tw/upload/images/20190930/20106426GPkogMamX9.jpg
當你輸入文字時會自動出現相對應的結果。打 "H" 就會出現 "H" 開頭的結果提示你
https://ithelp.ithome.com.tw/upload/images/20190930/20106426blG6u3Z7U1.jpg
打 "Ha" 同理會出現 "Ha" 開頭的結果

我以前都會這樣做

其實這功能很常實作到,也不困難。我都直接用 Array.prototype.filter 資料然後秀出來就完成!

但原來這只適用資料量不大的情況。因為使用者輸入一次你就要 filter 一次,假如使用者頻繁輸入就可能會影響到效能

解決辦法

Debounce

https://ithelp.ithome.com.tw/upload/images/20240616/20106426oYxyb8bGLS.png
2627. Debounce
設一個 timeout,例如輸入以後過兩秒才去抓一次使用者輸入值

function debounce(func, delay){
  // timeout 初始值
  let timeout = null;
  return function(...args){
    clearTimeout(timeout)

    timeout = setTimeout(() => {
      func(...args)
    }, delay)
  }

}
debounce(function(e){
        console.log(e.target.value);
}, 2000)

原始碼
https://ithelp.ithome.com.tw/upload/images/20191002/20106426sy2aaxNKjA.jpg
當你輸入 "H" 過 2 秒就會 print "H"(實務上就是過 2 秒才 autocomplete 去抓相關資料)。這應該沒甚麼問題
https://ithelp.ithome.com.tw/upload/images/20191002/20106426kJIzDPCQzK.jpg
但當使用者一直頻繁輸入,

  • 第 0 秒時輸入 "H",程式會把 "H" 放入 event queue 裡面不執行,等待兩秒後再執行
  • 使用者又在第 1 秒時輸入 "a",這時清掉 event queue 的東西(clearTimeout),重新放 "Ha" 進 event queue,從新等待 2 秒後再執行
  • 在第 2 秒時又輸入 "sssss",這時再次清掉 event queue 的東西,重新放 "Hasssss" 進 event queue,重新等待 2 秒後再執行
  • 第 4 秒時,印出 "Hasssss"

好處就是可以防止 js 頻繁去篩選資料,等待兩秒後再一次篩選就好

Throttle

https://ithelp.ithome.com.tw/upload/images/20240616/20106426rH28gh5Egm.png
2676. Throttle
它防止一下輸入太頻繁的值,所以會限制一個時間,第一次結果會馬上顯示,然後會在 wait 時間內顯示最後一次存得值

function throttle(func, wait) {
  let waiting = false, lastArgs = null;
  // 紀錄最 wait 時間內最後的值
  return (...args) => {
    if(!waiting){
      func(...args) // 第一次一定 trigger func
      waiting = true;
      let timeout = () => setTimeout(() => {
        waiting = false; // 在還沒有到下一次 wait 都不會 trigger func
        if(lastArgs){
          func(...lastArgs);
          waiting = true;
          lastArgs = null;
          timeout();
        }
      }, wait);

      timeout();
    }
    else {
      lastArgs = args //持續存值
    }
  }
}
throttle(function(e){
        console.log(e.target.value);
}, 2000)

https://ithelp.ithome.com.tw/upload/images/20191002/20106426qGad5ih6IS.jpg
當你第 0 秒輸入 "H" 馬上會印 "H",接下來兩秒內程式都不會再印東西
https://ithelp.ithome.com.tw/upload/images/20191002/20106426xs5ywdYN8R.jpg

直到第 2 秒才會印出來。所以以此類推在 第 0 秒、第 2 秒、第 4 秒時才會印出東西。

看到這邊應該可以感受到 Debounce 跟 Throttle 不同了。以輸入這個例子我是覺得會比較適合用 Debounce。但如果是偵測滑鼠移動 Throttle 就比較適合了。

這邊有我試做的 範例 可以上去玩玩看

  • Debounce: This technique delays the execution of a function until after a certain amount of time has passed.
  • Throttle: Throttling limits the rate at which a function is executed.

參考資料

如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您

歡迎追蹤我的部落格,除了技術文也會分享一些在矽谷工作的甘苦。


上一篇
[LeetCode #167] Two Pointer
下一篇
夢想與現實的差距之國外工作亂聊最終章
系列文
前端工程師用 javaScript 學演算法32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言